package com.dao;

import com.util.IDUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 对增删改查的简单封装使得继承类不用再去实现基本的增删改查
 * 数据表的命名规范：主键必须为id
 * Bean类的命名规范：M对应的就是Bean类，Bean类的成员变量应只含有数据表的字段
 * 调用规范：使用insert不用设置id和date，使用update时不用设置date
 * @param <M>
 */
public abstract class BaseAbstractDao<M> {

    public Class<M> getClazz() {
        Type t = getClass().getGenericSuperclass();
        Type[] params = ((ParameterizedType) t).getActualTypeArguments();
        return (Class<M>) params[0];
    }

    @Autowired
    JdbcTemplate jdbcTemplate;

    public List<M> selectAll(){
        String sql="select * from "+getClazz().getSimpleName().toLowerCase();
        RowMapper<M> rowMapper = new BeanPropertyRowMapper<>(getClazz());
        List<M> list = jdbcTemplate.query(sql,rowMapper);
        return list;
    }

    public M selectById(String id){
        String sql = "select * from "+ getClazz().getSimpleName().toLowerCase()+"where id = ?";
        RowMapper<M> rowMapper = new BeanPropertyRowMapper<>(getClazz());
        M m = jdbcTemplate.queryForObject(sql,rowMapper,id);
        return m;
    }

    public boolean deleteById(String id){
        String sql = "delete from "+getClazz().getSimpleName().toLowerCase()+" where id = ?";
        int count = jdbcTemplate.update(sql,id);
        return count>0;
    }

    public boolean insert(M m){
        String sql="insert into "+m.getClass().getSimpleName().toLowerCase()+"(";
        String ext="values(";
        ArrayList<Object> datas=new ArrayList<>();
        try {
            Field[] fields=m.getClass().getDeclaredFields();
            for(int i=0;i<fields.length;i++){
                fields[i].setAccessible(true);
                if(fields[i].get(m)!=null){
                    sql=sql+fields[i].getName()+",";
                    ext=ext+"?,";
                    datas.add(fields[i].get(m));
                }else if(fields[i].getName().equals("id")){
                    sql=sql+"id,";
                    ext=ext+"?,";
                    datas.add(IDUtil.getId());
                }else if (fields[i].getName().equals("date")){
                    sql=sql+"date,";
                    ext=ext+"?,";
                    datas.add(new Date());
                }
            }
            sql=sql.substring(0,sql.length()-1)+")";
            ext=ext.substring(0,ext.length()-1)+")";
            sql=sql+" "+ext;
            int cout=jdbcTemplate.update(sql,datas.toArray());
            return cout>0;
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return false;
    }

    public boolean update(M m){
        String sql = "update "+m.getClass().getSimpleName().toLowerCase()+" set";
        ArrayList<Object> datas=new ArrayList<>();
        try {
            Field[] fields=m.getClass().getDeclaredFields();
            for(int i=0;i<fields.length;i++){
                fields[i].setAccessible(true);
                if(fields[i].get(m)!=null&&fields[i].getName()!="id"){
                    sql=sql+" "+fields[i].getName()+"=?,";
                    datas.add(fields[i].get(m));
                }else if (fields[i].getName().equals("date")){
                    sql=sql+" date=?,";
                    datas.add(new Date());
                }
            }
            Field field=m.getClass().getDeclaredField("id");
            field.setAccessible(true);
            sql=sql.substring(0,sql.length()-1)+" where id=?";
            datas.add(field.get(m));
            int cout=jdbcTemplate.update(sql,datas.toArray());
            return cout>0;
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
        return false;
    }
}
